﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Collections;
using System.Web.Configuration;
using TextMining.Helper;

namespace DocumentMining.Topic
{

    public class Website
    {
        #region Properties

        //private List<int> _listPos;
        //private SortedList<string, int> _sortListWords;
        //private ArrayList _keyWord;


        public Hashtable HashWords;   //Store words with it's weight        
        public List<int> ListPos;
        public List<MyStatament> Statement { get; set; }  
        public string Id { get; set; }
        public string Url { get; set; }
        public List<string> RawData { get; set; }
        public string Group { get; set; }
        public List<MyWords> ListWords { get; set; }

        //public ArrayList KeyWord
        //{
        //    get { return _keyWord; }
        //    set { _keyWord = value; }
        //}

        #endregion

        #region Method

        public Website()
        {
            this.Id = System.Guid.NewGuid().ToString();
            this.Url = string.Empty;
            this.Group = string.Empty;
            this.RawData = new List<string>();
            this.Statement = new List<MyStatament>();
            this.ListPos = new List<int>();
            // this.SortListWords = new SortedList<string, int>();
            HashWords = new Hashtable();
        }

        public void CreateWebsiteInfo()
        {

            if (this.RawData != null)
            {
                ListWords = new List<MyWords>();

                for (int i = 0; i < this.RawData.Count; i++)
                {
                    MyWords myWords = new MyWords();
                    if (i == 0)
                    {
                        myWords.Word = RawData[0].ToString();
                        myWords.Count = 1;
                        myWords.Next = new List<MyWords>();
                        MyWords nextWord = new MyWords();
                        nextWord.Word = RawData[1].ToString();
                        myWords.Next.Add(nextWord);
                        myWords.Previous = null;

                    }
                    else
                    {
                        int iPos = FindWordInList(RawData[i].ToString(), ListWords);
                        if (iPos > -1)  // Exist word  in list
                        {
                            MyWords exsitWord = new MyWords();
                            exsitWord = ListWords[iPos];
                            exsitWord.Count += 1;
                            MyWords prevtWord = new MyWords();
                            prevtWord.Word = RawData[i - 1].ToString();
                            exsitWord.Previous = new List<MyWords>();
                            exsitWord.Previous.Add(prevtWord);

                            if (i == RawData.Count - 1) // the last word
                            {

                                exsitWord.Next = null;
                            }
                            else // Not last word
                            {
                                exsitWord.Next = new List<MyWords>();
                                MyWords nextWord = new MyWords();
                                nextWord.Word = RawData[i + 1].ToString();
                                exsitWord.Next.Add(nextWord);
                            }
                            ListWords[iPos] = exsitWord;
                        }
                        else  //No exist word
                        {
                            myWords.Word = RawData[i].ToString();
                            myWords.Count = 1;
                            myWords.Next = new List<MyWords>();
                            myWords.Previous = new List<MyWords>();
                            MyWords prevWord = new MyWords();
                            prevWord.Word = RawData[i - 1].ToString();
                            myWords.Previous.Add(prevWord);
                            if (i == RawData.Count - 1) //The last word
                            {
                                myWords.Next = null;
                            }
                            else //Not last word
                            {
                                MyWords nextWord = new MyWords();
                                nextWord.Word = RawData[i + 1].ToString();
                                myWords.Next.Add(nextWord);
                            }
                        }
                    }
                    ListWords.Add(myWords);
                }
            }

            RemoveBlank();
            CreateWordsList();
            RemoveSameWords();
            SortListWords("desc");
            CreateHashtableWords();
            AverageStatement();
            GetListKeyWords();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sDicrection">desc or asc</param>
        public void SortListWords(string sDicrection)
        {
            //ListWords.OrderBy(x => x.Count);
            ListWords.Sort(
                delegate(MyWords p1, MyWords p2)
                {
                    return p1.Count.CompareTo(p2.Count);
                }
                );
            if (string.Equals(sDicrection, "desc"))
                ListWords.Reverse();
        }

        public void CreateHashtableWords()
        {
            try
            {
                if (ListWords.Count > 0)
                {
                    foreach (MyWords item in ListWords)
                    {
                        //SortListWords.Add(item.Word, Convert.ToInt16(item.Count));
                        if (!HashWords.ContainsKey(item.Word))
                            HashWords.Add(item.Word, Convert.ToInt16(item.Count));
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.FrameworkLogger.Error("Add to hashtable ",ex);
            }

            
        }

        public void RemoveBlank()
        {
            if (ListWords.Count > 0)
            {
                for (int i = ListWords.Count - 1; i >= 0; i--)
                {
                    if (string.IsNullOrEmpty(ListWords[i].Word.ToString()) || ListWords[i].Word.ToString() == "")
                    {
                        ListWords.RemoveAt(i);
                    }
                }
            }
        }

        public void CreateWordsList()
        {
            if (ListWords.Count > 0)
            {
                for (int i = ListWords.Count - 1; i >= 0; i--)
                {
                    if (!string.IsNullOrEmpty(ListWords[i].Word) && ListWords[i].Word != "")
                    {
                        int iCount = CountWord(ListWords[i].Word, ListWords);

                        int iLastItemPos = ListPos.Count - 1;
                        for (int j = 0; j < ListPos.Count - 1; j++)
                        {
                            ListWords[ListPos[j]].Count = iCount;

                        }
                        //ListWords[ListPos[iLastItemPos]].Count = iCount;
                        ListPos.RemoveAll(item => item >= 0);
                    }
                }


            }
        }

        public void RemoveSameWords()
        {
            if (ListWords.Count > 0)
            {
                for (int i = ListWords.Count - 1; i > 0; i--)
                {
                    for (int j = i - 1; j >= 0; j--)
                    {
                        if (string.Equals(ListWords[j].Word.ToLower(), ListWords[i].Word.ToLower()))
                        {
                            ListWords.RemoveAt(i);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Find sWord in List 
        /// </summary>
        /// <param name="sWord"></param>
        /// <param name="listWords"></param>
        /// <returns>Return position if have and -1 if no have</returns>
        public int FindWordInList(string sWord, List<MyWords> listWords)
        {
            int iPos = 0;
            foreach (MyWords item in listWords)
            {
                if (string.Equals(sWord, item.Word))
                {
                    return iPos;
                }
                iPos++;
            }
            if (iPos == listWords.Count)
                return -1;
            return iPos;
        }

        public int CountWord(string sWord, List<MyWords> listWords)
        {
            int iResult = 0;
            for (int i = listWords.Count - 1; i >= 0; i--)
            {
                if (string.Equals(sWord.ToLower(), listWords[i].Word.ToLower()))
                {
                    iResult++;
                    ListPos.Add(i);
                }
            }

            return iResult;
        }


        public List<MyStatament> GetListKeyWords()
        {
            List<MyStatament> lstResult = new List<MyStatament>();
            List<MyStatament> lstSub = new List<MyStatament>();
            int iNumWords = Convert.ToInt32(WebConfigurationManager.AppSettings["numWords"].ToString());
            for (int i = 0; i < iNumWords; i++)
            {
                string sWords = ListWords[i].Word;
                lstSub = FindStatmentContainsWord(sWords);
                foreach (MyStatament item in lstSub)
                {
                    //foreach (MyStatament itemResult in lstResult)
                    //{
                    //    //if (!string.Equals(itemResult.Statament, item.Statament))
                            
                    //}
                    lstResult.Add(item);
                }
            }
            return lstResult;
        }

        /// <summary>
        /// Return list of statemnt contains this words
        /// </summary>
        /// <param name="sWord"></param>
        /// <returns></returns>
        public List<MyStatament> FindStatmentContainsWord(string sWord)
        {
            List<MyStatament> lstResult = new List<MyStatament>();

            if (Statement.Count > 0)
            {
                foreach (MyStatament item in Statement)
                {
                    if (item.Statament.Contains(sWord))
                    {
                        lstResult.Add(item);
                    }
                }
            }
            lstResult.Sort(
                delegate(MyStatament p1, MyStatament p2)
                {
                    return p1.dAverage.CompareTo(p2.dAverage);
                }
                );
            lstResult.Reverse();
            int numStatementConfig = Convert.ToInt32(WebConfigurationManager.AppSettings["numStatement"]);
            if (lstResult.Count > numStatementConfig)
            {
                for (int j = lstResult.Count - 1; j >= numStatementConfig; j--)
                {
                    lstResult.RemoveAt(j);
                }
            }
            return lstResult;
        }

        //public List<string> FindStatementMax(string sWords, List<string> sList)
        //{
        //    List<string> lstResult = new List<string>();
        //    if (sList.Count > 0)
        //    {

        //    }
        //    return lstResult;
        //}

        public void AverageStatement()
        {
            double dResult = 0;
            if (Statement.Count > 0)
            {
                foreach (MyStatament item in Statement)
                {
                    if (item.Statament.Length > 0)
                    {
                        string[] sArr = item.Statament.Split(' ');
                        if (sArr.Length > 0)
                        {
                            foreach (string str in sArr)
                            {
                                dResult += Convert.ToInt32(HashWords[str]);
                            }
                            dResult = dResult / sArr.Length;
                        }
                        else
                            dResult = 0;
                    }
                    else
                        dResult = 0;

                    item.dAverage = dResult;
                }

            }
        }

        #endregion

    }

    public class MyStatament
    {
        private string _statement;
        private double _dAverage;

        public string Statament
        {
            get { return _statement; }
            set { _statement = value; }
        }

        public double dAverage
        {
            get { return _dAverage; }
            set { _dAverage = value; }
        }

    }
}